using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Reflection;
using System.Text;
using System.Web;
using Castle.ActiveRecord;
using NHibernate.Expression;

namespace WOODIFramework.Model
{
    [Serializable]
    public struct ActiveRecordObject
    {
        public string PrimaryKeyValue;
        public System.Type ObjectType;
    }

    [ActiveRecord("Page"), JoinedBase]
    public class Page : ActiveRecordBase<Page>
    {
        #region Fields

        private Guid _id;
        private String _name;
        private IList _items = new ArrayList();
        private Dictionary<string, ActiveRecordBase> _boundObjects;
        private Dictionary<string, ActiveRecordBase[]> _boundCollections;
        private Dictionary<string, Type> _boundCollectionsType = new Dictionary<string,Type>();
        private Dictionary<string, ActiveRecordObject> _requiredObjects = new Dictionary<string, ActiveRecordObject>();
        private Dictionary<string, ActiveRecordObject[]> _requiredCollections = new Dictionary<string, ActiveRecordObject[]>();
        private Dictionary<string, string[]> _requiredObjectsProperties = new Dictionary<string, string[]>();
        private Dictionary<string, string[]> _requiredCollectionsProperties = new Dictionary<string, string[]>();
        private Dictionary<string, string> _requiredObjectsMethod = new Dictionary<string, string>();
        private Dictionary<string, string> _requiredCollectionsMethod = new Dictionary<string, string>();
        private Dictionary<string, Object> _requestProperties;

        #endregion

        #region Properties

        [PrimaryKey(PrimaryKeyType.Assigned)]
        public Guid Id
        {
            get { return _id; }
            set { _id = value; }
        }

        [Property]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        [HasAndBelongsToMany(typeof(PageItem),
        Table = "PageItemPage", ColumnKey = "PageId", ColumnRef = "PageItemId")]
        public IList Items
        {
            get { return _items; }
            set { _items = value; }
        }

        [Property]
        public Dictionary<string, ActiveRecordObject> RequiredObjects
        {
            get { return _requiredObjects; }
            set { _requiredObjects = value; }
        }

        [Property]
        public Dictionary<string, ActiveRecordObject[]> RequiredCollections
        {
            get { return _requiredCollections; }
            set { _requiredCollections = value; }
        }

        public Dictionary<string, ActiveRecordBase> BoundObjects
        {
            get
            { 
                if (_boundObjects == null)
                {
                    _boundObjects = new Dictionary<string, ActiveRecordBase>();
                    foreach(KeyValuePair<string, ActiveRecordObject> requiredObjectEntry in this.RequiredObjects)
                    {
                        ActiveRecordObject arObject = requiredObjectEntry.Value;
                        Type consoleType = arObject.ObjectType;
                        string methodName = null;
                        if (this.RequiredObjectsMethod.ContainsKey(requiredObjectEntry.Key))
                        { methodName = this.RequiredObjectsMethod[requiredObjectEntry.Key]; }
                        else
                        { methodName = "FindByID"; }
                        MethodInfo findByPrimaryKey = consoleType.GetMethod(methodName);
                        Object obj = null;
                        Object[] objectProperties = new Object[this.RequiredObjectsProperties[requiredObjectEntry.Key].GetLength(0)];

                            for (int objectPropertyPosition = 0; objectPropertyPosition < this.RequiredObjectsProperties[requiredObjectEntry.Key].GetLength(0); objectPropertyPosition++)
                            {
                                string objectProperty = this.RequiredObjectsProperties[requiredObjectEntry.Key][objectPropertyPosition];
                                object requestObject = this.RequestProperties[objectProperty];//];
                                objectProperties[objectPropertyPosition] = requestObject;
                            }
                            obj = (Object)findByPrimaryKey.Invoke(null, objectProperties);//arObject.PrimaryKeyValue});
                        if (obj.GetType().BaseType.Name != typeof(ActiveRecordBase<object>).Name & obj.GetType().BaseType.Name != "Array")
                        { throw new Exception("Only Active Record objects are supported at the moment"); }
                        _boundObjects.Add(requiredObjectEntry.Key, (ActiveRecordBase)obj);
                    }
                }
                return _boundObjects;
            }
            set { _boundObjects = value; }
        }

        public Dictionary<string, ActiveRecordBase[]> BoundCollections
        {
            get
            {
                if (_boundCollections == null)
                {
                    _boundCollections = new Dictionary<string, ActiveRecordBase[]>();
                    foreach (KeyValuePair<string, ActiveRecordObject[]> requiredCollectionEntry in this.RequiredCollections)
                    {
                        ActiveRecordObject[] arCollection = requiredCollectionEntry.Value;
                        Type consoleType = BoundCollectionsType[requiredCollectionEntry.Key];
                        string methodName = this.RequiredObjectsMethod[requiredCollectionEntry.Key];
                        if (methodName == null)
                        { methodName = "FindByID"; }
                        MethodInfo findByPrimaryKey = consoleType.GetMethod(methodName);
                        Object obj = null;
                        if (this.RequiredObjectsProperties.Count > 0)
                        {
                            Object[] objectProperties = new Object[this.RequiredObjectsProperties[requiredCollectionEntry.Key].GetLength(0)];

                            for (int objectPropertyPosition = 0; objectPropertyPosition < this.RequiredObjectsProperties[requiredCollectionEntry.Key].GetLength(0); objectPropertyPosition++)
                            {
                                string objectProperty = this.RequiredObjectsProperties[requiredCollectionEntry.Key][objectPropertyPosition];
                                object requestObject = this.RequestProperties[objectProperty];//];
                                objectProperties[objectPropertyPosition] = requestObject;
                            }
                            obj = (Object)findByPrimaryKey.Invoke(null, objectProperties);//arObject.PrimaryKeyValue});
                        }
                        else
                        {
                            obj = (Object)findByPrimaryKey.Invoke(null, null);
                        }
                        if (obj.GetType().BaseType.Name != "Array")
                        { throw new Exception("Only Active Record collections are supported at the moment"); }
                        _boundCollections.Add(requiredCollectionEntry.Key, (ActiveRecordBase[])obj);
                    }
                }
                return _boundCollections;
            }
            set { _boundCollections = value; }
        }

        public Dictionary<string, Object> RequestProperties
        {
            get
            {
                if (_requestProperties == null)
                {
                    _requestProperties = new Dictionary<string, Object>();
                    Assembly webAssembly = Assembly.GetEntryAssembly();
                    
                    foreach(string requestParam in HttpContext.Current.Request.Params.Keys)
                    {
                        _requestProperties.Add(requestParam, HttpContext.Current.Request.Params[requestParam]);
                    }
                }
                return _requestProperties; 
            }
        }

        [Property]
        public Dictionary<string, Type> BoundCollectionsType
        {
            get { return _boundCollectionsType; }
            set { _boundCollectionsType = value; }
        }

        [Property]
        public Dictionary<string, string[]> RequiredObjectsProperties
        {
            get { return _requiredObjectsProperties; }
            set { _requiredObjectsProperties = value; }
        }

        [Property]
        public Dictionary<string, string[]> RequiredCollectionsProperties
        {
            get { return _requiredCollectionsProperties; }
            set { _requiredCollectionsProperties = value; }
        }

        [Property]
        public Dictionary<string, string> RequiredObjectsMethod
        {
            get { return _requiredObjectsMethod; }
            set { _requiredObjectsMethod = value; }
        }

        [Property]
        public Dictionary<string, string> RequiredCollectionsMethod
        {
            get { return _requiredCollectionsMethod; }
            set { _requiredCollectionsMethod = value; }
        }

        #endregion

        #region Public Methods

        #region Public Static Methods
        /*
        public static Page CreatePage()
        {
            return new Page();
        }

        public static Page CreatePage(string Name)
        {
            return new Page(Name);
        }
        */
        public static Page FindPageByPageName(string Name)
        {
            ICriterion criteria = Expression.Eq("Name", Name);
            Page page = Page.FindFirst(criteria);
            return page;
        }
        
        #endregion

        public string RenderHTML()
        {
            
            StringBuilder pageHTML = new StringBuilder();
            foreach (PageItem pageItem in Items)
            {
                pageItem.BoundObjects = this.BoundObjects;
                pageItem.BoundCollections = this.BoundCollections;
                switch (pageItem.GetType().ToString())
                {
                    case "WOODIFramework.Model.Label":
                        pageHTML.Append(((Model.Label)pageItem).RenderHTML());
                        break;
                    case "WOODIFramework.Model.TextBox":
                        //pageHTML = ProcessTextBox((Model.TextBox)pageItem, page);
                        break;
                    case "WOODIFramework.Model.SubmitButton":
                        //pageHTML = ProcessSubmitButton((Model.SubmitButton)pageItem, page);
                        break;
                    case "WOODIFramework.Model.BasicGrid":
                        pageHTML.Append(((Model.BasicGrid)pageItem).RenderHTML());
                        break;
                }
            }
            return pageHTML.ToString();
        }

        #endregion


    }
}
